package com.openlogic.common.core.utils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import cn.hutool.core.util.ArrayUtil;

public class GenericUtil {

	public static ParameterizedType toParameterizedType(Type type) {
		ParameterizedType result = null;
		if (type instanceof ParameterizedType) {
			result = (ParameterizedType) type;
		} else if (type instanceof Class) {
			final Class<?> clazz = (Class<?>) type;
			Type genericSuper = clazz.getGenericSuperclass();
			if (null == genericSuper || Object.class.equals(genericSuper)) {
				// 如果类没有父类，而是实现一些定义好的泛型接口，则取接口的Type
				final Type[] genericInterfaces = clazz.getGenericInterfaces();
				if (ArrayUtil.isNotEmpty(genericInterfaces)) {
					// 默认取第一个实现接口的泛型Type
					genericSuper = genericInterfaces[0];
				}
			}
			result = toParameterizedType(genericSuper);
		}
		return result;
	}

	public static Class<?> getInterfaceGenericType(Class<?> clazz, int index) {
		final Type[] genericInterfaces = clazz.getGenericInterfaces();
		final ParameterizedType genericInterface = toParameterizedType(genericInterfaces[0]);
		final Type type = genericInterface.getActualTypeArguments()[index];
		return checkType(type, index);
	}

	private static Class<?> checkType(Type type, int index) {
		if (type instanceof Class<?>) {
			return (Class<?>) type;
		} else if (type instanceof ParameterizedType) {
			ParameterizedType pt = (ParameterizedType) type;
			Type t = pt.getActualTypeArguments()[index];
			return checkType(t, index);
		} else {
			String className = type == null ? "null" : type.getClass().getName();
			throw new IllegalArgumentException("Unsupported type: " + className);
		}
	}

	public static Class<?> getSuperClassGenericType(Class<?> clazz, int index) {
		final Type genericSuperclass = clazz.getGenericSuperclass();
		if (!(genericSuperclass instanceof ParameterizedType)) {
			return Object.class;
		}
		final Type[] params = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
		if (index >= params.length || index < 0) {
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			return Object.class;
		}
		return (Class<?>) params[index];
	}

}
